#pragma once
#include <cstdio>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include <stdarg.h>
#include <unistd.h>
#include <pthread.h>

#include "LockGuard.hpp"

const std::string logname = "./log.txt";

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
bool ToFile = false;

enum Level
{
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

const std::string I2LevelStr[5] = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};

std::string GetTimestr()
{
    time_t cur_time = time(NULL);
    struct tm *format_time = localtime(&cur_time);

    char buffer[1024] = {0};
    snprintf(buffer, sizeof(buffer) - 1, "%d-%d-%d %d-%d-%d", format_time->tm_year + 1900, format_time->tm_mon + 1, format_time->tm_mday, format_time->tm_hour, format_time->tm_min, format_time->tm_sec);

    return buffer;
}

void SaveFile(std::string &message, std::string pathname = logname)
{
    std::ofstream out(pathname, std::ios_base::app);
    if (!out.is_open())
    {
        return;
    }

    out << message;
    out.close();
}

void LogMessage(std::string filename, int linenum, int level, const char *format, ...)
{
    std::string levelstr = I2LevelStr[level];
    std::string timestr = GetTimestr();

    char buffer[1024] = {0};
    va_list arg;
    va_start(arg, format);
    vsnprintf(buffer, sizeof(buffer) - 1, format, arg);
    va_end(arg);

    std::string message = "[" + timestr + "]" +
                          "[" + levelstr + "]" + "[" + "pid:" + std::to_string(getpid()) + "]" +
                          "[" + filename + "]" + "[" + std::to_string(linenum) + "] " + buffer + "\n";

    LockGuard lock(&mutex);

    if (!ToFile)
        std::cout << message;
    else
        SaveFile(message);
}

// ##__VA_ARGS__ 表示可变参数
#define LOG(level, format, ...) do{LogMessage(__FILE__, __LINE__, level, format, ##__VA_ARGS__); } while (0)                                                       